using System.Collections.Generic;
using System.Threading.Tasks;
using GameKit.Core;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Pool;

namespace GameKitUnity.Core
{
    public class PoolManager
    {
        public static PoolManager Instance { get; } = new();
        private const string RootName = "Pool Objectsr";

        private readonly Dictionary<string, ObjectPool<GameObject>> _pools = new();
        private readonly Dictionary<GameObject, ObjectPool<GameObject>> _objectPools = new();

        public void Initialize()
        {
            var root = GameObject.Find(RootName);
            if (root == null)
            {
                root = new GameObject(RootName);
            }
        }

        public async Task Create(object target, string key, AssetReferenceGameObject asset, int count, int maxSize = 100)
        {
            var prefab = await AssetLoader.Instance.LoadAsync<GameObject>(target, asset);
            Create(key, prefab, count, maxSize);
        }

        public void Create(string key, GameObject prefab, int count, int maxSize = 100)
        {
            if (_pools.TryGetValue(key, out var pool))
            {
                Log.Error($"Pool with key {key} already exists");
            }
            else
            {
                pool = new ObjectPool<GameObject>(
                    () =>
                    {
                        var go = Object.Instantiate(prefab);

                        return go;
                    },
                    go => { go.SetActive(true); },
                    go => { go.SetActive(false); },
                    Object.Destroy,
                    false,
                    count,
                    maxSize);
                _pools.Add(key, pool);
            }
        }

        public GameObject Get(string key)
        {
            if (_pools.TryGetValue(key, out var pool))
            {
                var go = pool.Get();
                _objectPools[go] = pool;
                return go;
            }

            Log.Error($"Pool with key {key} not found");
            return null;
        }

        public void Release(string key, GameObject gameObject)
        {
            if (_pools.TryGetValue(key, out var pool))
            {
                pool.Release(gameObject);
            }
            else
            {
                Log.Error($"Pool with key {key} not found");
            }
        }

        public void Release(GameObject gameObject)
        {
            if (_objectPools.TryGetValue(gameObject, out var pool))
            {
                pool.Release(gameObject);
            }
            else
            {
                Log.Error($"GameObject {gameObject.name} not found in any pool");
            }
        }
    }
}